﻿namespace UnityEditor.Graphs.AnimationStateMachine
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Runtime.CompilerServices;
    using System.Runtime.InteropServices;
    using UnityEditor;
    using UnityEditor.Graphs;
    using UnityEditorInternal;
    using UnityEngine;

    internal class GraphGUI : UnityEditor.Graphs.GraphGUI
    {
        private LiveLinkInfo m_LiveLinkInfo;

        private void AddStateEmptyCallback(object data)
        {
            Undo.RegisterUndo(this.activeStateMachine, "Empty State Added");
            this.activeStateMachine.CreateStateWithMotion((Vector3) ((Vector2) data), null);
            AnimatorControllerTool.tool.RebuildGraph();
        }

        private void AddStateFromNewBlendTreeCallback(object data)
        {
            Undo.RegisterUndo(this.activeStateMachine, "Blend Tree State Added");
            BlendTree objectToAdd = new BlendTree {
                name = "Blend Tree"
            };
            objectToAdd.SetBlendEvent(this.tool.animatorController.GetDefaultBlendTreeEvent());
            objectToAdd.hideFlags = HideFlags.HideInHierarchy;
            AssetDatabase.AddObjectToAsset(objectToAdd, this.activeStateMachine);
            this.activeStateMachine.CreateStateWithMotion((Vector3) ((Vector2) data), objectToAdd);
            AnimatorControllerTool.tool.RebuildGraph();
        }

        private void AddStateFromSelectedMotionCallback(object data)
        {
            Undo.RegisterUndo(this.activeStateMachine, "Clip State Added");
            Motion activeObject = Selection.activeObject as Motion;
            this.activeStateMachine.CreateStateWithMotion((Vector3) ((Vector2) data), activeObject);
            AnimatorControllerTool.tool.RebuildGraph();
        }

        private void AddStateMachineCallback(object data)
        {
            Undo.RegisterUndo(this.activeStateMachine, "Sub-State Machine Added");
            this.activeStateMachine.AddStateMachine("New StateMachine", this.rootStateMachine);
            this.activeStateMachine.SetStateMachinePosition((int) (this.activeStateMachine.GetStateMachineCount() - 1), (Vector3) ((Vector2) data));
            AnimatorControllerTool.tool.RebuildGraph();
        }

        public void ClearSelection()
        {
            base.selection.Clear();
            this.edgeGUI.edgeSelection.Clear();
            this.UpdateUnitySelection();
        }

        private void CopyStateMachineCallback(object data)
        {
            this.activeStateMachine.SyncLocalTransitionsFrom(this.rootStateMachine);
            Unsupported.CopyStateMachineToPasteboard(this.activeStateMachine);
        }

        protected bool DeleteEvent()
        {
            Event current = Event.current;
            if ((current.type != EventType.KeyDown) && (current.keyCode == KeyCode.Delete))
            {
                return true;
            }
            if ((current.commandName != "SoftDelete") && (current.commandName != "Delete"))
            {
                return false;
            }
            if (current.type == EventType.ValidateCommand)
            {
                current.Use();
                return false;
            }
            return (current.type == EventType.ExecuteCommand);
        }

        private void HandleContextMenu()
        {
            if (Event.current.type == EventType.ContextClick)
            {
                GenericMenu menu = new GenericMenu();
                menu.AddItem(new GUIContent("Create State/Empty"), false, new GenericMenu.MenuFunction2(this.AddStateEmptyCallback), Event.current.mousePosition);
                if (HasMotionSelected())
                {
                    menu.AddItem(new GUIContent("Create State/From Selected Clip"), false, new GenericMenu.MenuFunction2(this.AddStateFromSelectedMotionCallback), Event.current.mousePosition);
                }
                else
                {
                    menu.AddDisabledItem(new GUIContent("Create State/From Selected Clip"));
                }
                menu.AddItem(new GUIContent("Create State/From New Blend Tree"), false, new GenericMenu.MenuFunction2(this.AddStateFromNewBlendTreeCallback), Event.current.mousePosition);
                menu.AddItem(new GUIContent("Create Sub-State Machine"), false, new GenericMenu.MenuFunction2(this.AddStateMachineCallback), Event.current.mousePosition);
                if (Unsupported.HasStateMachineDataInPasteboard())
                {
                    menu.AddItem(new GUIContent("Paste"), false, new GenericMenu.MenuFunction2(this.PasteCallback), Event.current.mousePosition);
                }
                else
                {
                    menu.AddDisabledItem(new GUIContent("Paste"));
                }
                menu.AddItem(new GUIContent("Copy current StateMachine"), false, new GenericMenu.MenuFunction2(this.CopyStateMachineCallback), Event.current.mousePosition);
                menu.ShowAsContext();
            }
        }

        private void HandleDeleteEvent()
        {
            if (this.DeleteEvent())
            {
                UnityEditor.Graphs.Node[] nodeArray = base.selection.ToArray();
                base.selection.Clear();
                List<string> list = new List<string>();
                foreach (UnityEditor.Graphs.AnimationStateMachine.Node node in nodeArray)
                {
                    if (node is StateNode)
                    {
                        list.Add((node as StateNode).state.GetName());
                    }
                    else if (node is StateMachineNode)
                    {
                        StateMachine stateMachine = (node as StateMachineNode).stateMachine;
                        if (this.parentStateMachine != stateMachine)
                        {
                            list.Add(stateMachine.GetName());
                        }
                    }
                }
                foreach (int num2 in this.edgeGUI.edgeSelection)
                {
                    foreach (Transition transition in this.stateMachineGraph.GetEdgeInfo(base.graph.edges[num2]).transitions)
                    {
                        list.Add(transition.GetUniqueName());
                    }
                }
                if (list.Count != 0)
                {
                    string title = "Delete selected asset";
                    if (list.Count > 1)
                    {
                        title = title + "s";
                    }
                    title = title + "?";
                    string message = string.Empty;
                    foreach (string str3 in list)
                    {
                        message = message + str3 + "\n";
                    }
                    message = message + "\nYou cannot undo this action.";
                    if (EditorUtility.DisplayDialog(title, message, "Delete", "Cancel"))
                    {
                        foreach (UnityEditor.Graphs.AnimationStateMachine.Node node2 in nodeArray)
                        {
                            if (node2 is StateNode)
                            {
                                UnityEditorInternal.State state = (node2 as StateNode).state;
                                BlendTree motion = state.GetMotion(AnimatorControllerTool.tool.motionSetIndex) as BlendTree;
                                if ((motion != null) && MecanimUtilities.AreSameAsset(motion, this.activeStateMachine))
                                {
                                    MecanimUtilities.DestroyBlendTreeRecursive(motion);
                                }
                                this.rootStateMachine.RemoveState(state);
                                this.stateMachineGraph.RemoveNode(node2);
                            }
                            if (node2 is StateMachineNode)
                            {
                                StateMachine machine2 = (node2 as StateMachineNode).stateMachine;
                                if (this.parentStateMachine != machine2)
                                {
                                    this.rootStateMachine.RemoveStateMachine(machine2);
                                    this.stateMachineGraph.RemoveNode(node2);
                                }
                            }
                            if (node2 is AnyStateNode)
                            {
                                base.selection.Add(node2);
                            }
                        }
                        foreach (int num4 in this.edgeGUI.edgeSelection)
                        {
                            foreach (Transition transition2 in this.stateMachineGraph.GetEdgeInfo(base.graph.edges[num4]).transitions)
                            {
                                this.rootStateMachine.RemoveTransition(transition2);
                            }
                            this.stateMachineGraph.RemoveEdge(base.graph.edges[num4]);
                        }
                        this.edgeGUI.edgeSelection.Clear();
                    }
                    this.UpdateUnitySelection();
                }
            }
        }

        private void HandleObjectDragging()
        {
            Event current = Event.current;
            List<Motion> draggedMotions = DragAndDrop.objectReferences.OfType<Motion>().ToList<Motion>();
            switch (current.type)
            {
                case EventType.DragUpdated:
                case EventType.DragPerform:
                    if (this.ValideDraggedMotion(ref draggedMotions, current.type == EventType.DragPerform))
                    {
                        DragAndDrop.visualMode = DragAndDropVisualMode.Generic;
                    }
                    else
                    {
                        DragAndDrop.visualMode = DragAndDropVisualMode.None;
                    }
                    if ((current.type == EventType.DragPerform) && (DragAndDrop.visualMode != DragAndDropVisualMode.None))
                    {
                        DragAndDrop.AcceptDrag();
                        Undo.RegisterUndo(this.activeStateMachine, "Drag motion to state machine.");
                        for (int i = 0; i < draggedMotions.Count; i++)
                        {
                            Motion motion = draggedMotions[i];
                            this.activeStateMachine.CreateStateWithMotion((Vector3) (current.mousePosition + (new Vector2(12f, 12f) * i)), motion);
                        }
                        this.stateMachineGraph.RebuildGraph();
                    }
                    current.Use();
                    break;

                case EventType.DragExited:
                    this.ValideDraggedMotion(ref draggedMotions, true);
                    current.Use();
                    break;
            }
        }

        private static bool HasMotionSelected()
        {
            return (Selection.activeObject is Motion);
        }

        private bool IsCurrentStateMachineNodeLiveLinked(UnityEditor.Graphs.AnimationStateMachine.Node n)
        {
            StateMachineNode node = n as StateMachineNode;
            if (node != null)
            {
                UnityEditorInternal.State currentState = this.liveLinkInfo.currentState;
                bool flag = this.activeStateMachine.HasState(currentState, true);
                bool flag2 = node.stateMachine.HasState(currentState, true);
                bool flag3 = node.stateMachine.HasStateMachine(this.activeStateMachine, false);
                if (((flag3 && flag2) && !flag) || (!flag3 && flag2))
                {
                    return true;
                }
            }
            return false;
        }

        private void LiveLink()
        {
            this.m_LiveLinkInfo.Clear();
            if (this.tool.liveLink)
            {
                Animator previewObject = this.tool.previewObject;
                AnimatorStateInfo currentAnimatorStateInfo = previewObject.GetCurrentAnimatorStateInfo(AnimatorControllerTool.tool.selectedLayerIndex);
                AnimatorStateInfo nextAnimatorStateInfo = previewObject.GetNextAnimatorStateInfo(AnimatorControllerTool.tool.selectedLayerIndex);
                AnimatorTransitionInfo animatorTransitionInfo = previewObject.GetAnimatorTransitionInfo(AnimatorControllerTool.tool.selectedLayerIndex);
                int nameHash = currentAnimatorStateInfo.nameHash;
                int stateUniqueNameHash = nextAnimatorStateInfo.nameHash;
                this.m_LiveLinkInfo.currentState = (nameHash == 0) ? null : this.rootStateMachine.FindState(nameHash);
                this.m_LiveLinkInfo.currentStateNormalizedTime = currentAnimatorStateInfo.normalizedTime;
                this.m_LiveLinkInfo.nextState = (stateUniqueNameHash == 0) ? null : this.rootStateMachine.FindState(stateUniqueNameHash);
                this.m_LiveLinkInfo.nextStateNormalizedTime = nextAnimatorStateInfo.normalizedTime;
                int transitionUniqueName = animatorTransitionInfo.nameHash;
                this.m_LiveLinkInfo.currentTransition = this.rootStateMachine.FindTransition(transitionUniqueName);
                this.m_LiveLinkInfo.currentTransitionProgress = animatorTransitionInfo.normalizedTime;
                bool flag = (transitionUniqueName != 0) && (this.m_LiveLinkInfo.currentTransition == null);
                if ((this.tool.autoLiveLink && (this.m_LiveLinkInfo.currentState != null)) && (this.m_LiveLinkInfo.nextState != null))
                {
                    StateMachine machine3;
                    StateMachine stateMachine = this.m_LiveLinkInfo.currentState.GetStateMachine();
                    StateMachine machine2 = (this.m_LiveLinkInfo.nextState == null) ? null : this.m_LiveLinkInfo.nextState.GetStateMachine();
                    if ((this.m_LiveLinkInfo.currentTransitionProgress < 0.5) && !flag)
                    {
                        machine3 = stateMachine;
                    }
                    else
                    {
                        machine3 = machine2;
                    }
                    if ((machine3 != this.activeStateMachine) && (Event.current.type == EventType.Repaint))
                    {
                        List<StateMachine> hierarchy = new List<StateMachine>();
                        MecanimUtilities.StateMachineRelativePath(this.rootStateMachine, machine3, ref hierarchy);
                        this.tool.BuildBreadCrumbsFromSMHierarchy(hierarchy);
                    }
                }
            }
        }

        public override void NodeGUI(UnityEditor.Graphs.Node n)
        {
            GUILayoutUtility.GetRect((float) 160f, (float) 0f);
            base.SelectNode(n);
            n.NodeUI(this);
            base.DragNodes();
        }

        public override void OnGraphGUI()
        {
            this.SyncGraphToUnitySelection();
            this.LiveLink();
            base.m_Host.BeginWindows();
            foreach (UnityEditor.Graphs.AnimationStateMachine.Node node in base.m_Graph.nodes)
            {
                <OnGraphGUI>c__AnonStorey13 storey = new <OnGraphGUI>c__AnonStorey13 {
                    <>f__this = this,
                    n2 = node
                };
                bool on = base.selection.Contains(node);
                GUILayoutOption[] options = new GUILayoutOption[] { GUILayout.Width(0f), GUILayout.Height(0f) };
                node.position = GUILayout.Window(node.GetInstanceID(), node.position, new GUI.WindowFunction(storey.<>m__31), node.title, UnityEditor.Graphs.Styles.GetNodeStyle(node.style, !this.IsCurrentStateMachineNodeLiveLinked(node) ? node.color : UnityEditor.Graphs.Styles.Color.Blue, on), options);
                if ((Event.current.type == EventType.MouseMove) && node.position.Contains(Event.current.mousePosition))
                {
                    this.edgeGUI.SlotDragging(node.inputSlots.First<Slot>(), true, true);
                }
            }
            this.edgeGUI.DoEdges();
            base.m_Host.EndWindows();
            if (Event.current.type == EventType.MouseDown)
            {
                this.edgeGUI.EndDragging();
            }
            this.HandleDeleteEvent();
            this.HandleContextMenu();
            this.HandleObjectDragging();
            base.DragSelection(new Rect(-5000f, -5000f, 10000f, 10000f));
            if (this.stateMachineGraph.DisplayDirty())
            {
                this.stateMachineGraph.RebuildGraph();
            }
            this.stateMachineGraph.ReadNodePositions();
        }

        private void PasteCallback(object data)
        {
            Undo.RegisterUndo(this.activeStateMachine, "Paste");
            int stateCount = this.activeStateMachine.GetStateCount();
            int stateMachineCount = this.activeStateMachine.GetStateMachineCount();
            Unsupported.PasteToStateMachineFromPasteboard(this.activeStateMachine, this.rootStateMachine);
            if (stateCount == (this.activeStateMachine.GetStateCount() - 1))
            {
                this.activeStateMachine.GetState(this.activeStateMachine.GetStateCount() - 1).SetPosition((Vector3) ((Vector2) data));
            }
            else if (stateMachineCount == (this.activeStateMachine.GetStateMachineCount() - 1))
            {
                this.activeStateMachine.SetStateMachinePosition(stateMachineCount, (Vector3) ((Vector2) data));
            }
            AnimatorControllerTool.tool.RebuildGraph();
        }

        private void SyncGraphToUnitySelection()
        {
            if (GUIUtility.hotControl == 0)
            {
                base.selection.Clear();
                foreach (UnityEngine.Object obj2 in Selection.objects)
                {
                    UnityEditor.Graphs.AnimationStateMachine.Node item = null;
                    UnityEditorInternal.State state = obj2 as UnityEditorInternal.State;
                    if (state != null)
                    {
                        item = this.stateMachineGraph.FindNode(state);
                    }
                    StateMachine stateMachine = obj2 as StateMachine;
                    if (stateMachine != null)
                    {
                        item = this.stateMachineGraph.FindNode(stateMachine);
                    }
                    AnyStateNode node2 = obj2 as AnyStateNode;
                    if (node2 != null)
                    {
                        item = this.stateMachineGraph.FindNode((UnityEditorInternal.State) null);
                    }
                    if (item != null)
                    {
                        base.selection.Add(item);
                    }
                }
            }
        }

        protected override void UpdateUnitySelection()
        {
            List<UnityEngine.Object> list = new List<UnityEngine.Object>();
            foreach (UnityEditor.Graphs.Node node in base.selection)
            {
                if (node is StateNode)
                {
                    list.Add((node as StateNode).state);
                }
                if (node is StateMachineNode)
                {
                    list.Add((node as StateMachineNode).stateMachine);
                }
                if (node is AnyStateNode)
                {
                    list.Add(node);
                }
            }
            if (list.Count == 0)
            {
                foreach (int num in this.edgeGUI.edgeSelection)
                {
                    EdgeInfo edgeInfo = this.stateMachineGraph.GetEdgeInfo(base.graph.edges[num]);
                    list.AddRange(edgeInfo.transitions.OfType<UnityEngine.Object>());
                }
            }
            Selection.objects = list.ToArray();
        }

        private bool ValideDraggedMotion(ref List<Motion> draggedMotions, bool showWarning)
        {
            for (int i = 0; i < draggedMotions.Count; i++)
            {
                Motion item = draggedMotions[i];
                if (!item.ValidateIfRetargetable(showWarning))
                {
                    draggedMotions.Remove(item);
                }
            }
            return (draggedMotions.Count > 0);
        }

        public StateMachine activeStateMachine
        {
            get
            {
                return this.stateMachineGraph.activeStateMachine;
            }
        }

        public override IEdgeGUI edgeGUI
        {
            get
            {
                if (base.m_EdgeGUI == null)
                {
                    UnityEditor.Graphs.AnimationStateMachine.EdgeGUI egui = new UnityEditor.Graphs.AnimationStateMachine.EdgeGUI {
                        host = this
                    };
                    base.m_EdgeGUI = egui;
                }
                return base.m_EdgeGUI;
            }
        }

        public LiveLinkInfo liveLinkInfo
        {
            get
            {
                return this.m_LiveLinkInfo;
            }
        }

        public StateMachine parentStateMachine
        {
            get
            {
                return this.stateMachineGraph.parentStateMachine;
            }
        }

        public StateMachine rootStateMachine
        {
            get
            {
                return this.stateMachineGraph.rootStateMachine;
            }
        }

        public UnityEditor.Graphs.AnimationStateMachine.Graph stateMachineGraph
        {
            get
            {
                return (base.graph as UnityEditor.Graphs.AnimationStateMachine.Graph);
            }
        }

        public AnimatorControllerTool tool
        {
            get
            {
                return (base.m_Host as AnimatorControllerTool);
            }
        }

        [CompilerGenerated]
        private sealed class <OnGraphGUI>c__AnonStorey13
        {
            internal UnityEditor.Graphs.AnimationStateMachine.GraphGUI <>f__this;
            internal UnityEditor.Graphs.AnimationStateMachine.Node n2;

            internal void <>m__31(int)
            {
                this.<>f__this.NodeGUI(this.n2);
            }
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct LiveLinkInfo
        {
            private UnityEditorInternal.State m_CurrentState;
            private float m_CurrentStateNormalizedTime;
            private UnityEditorInternal.State m_NextState;
            private float m_NextStateNormalizedTime;
            private Transition m_CurrentTransition;
            private float m_CurrentTransitionProgress;
            public UnityEditorInternal.State currentState
            {
                get
                {
                    return this.m_CurrentState;
                }
                set
                {
                    this.m_CurrentState = value;
                }
            }
            public float currentStateNormalizedTime
            {
                get
                {
                    return this.m_CurrentStateNormalizedTime;
                }
                set
                {
                    this.m_CurrentStateNormalizedTime = value;
                }
            }
            public UnityEditorInternal.State nextState
            {
                get
                {
                    return this.m_NextState;
                }
                set
                {
                    this.m_NextState = value;
                }
            }
            public float nextStateNormalizedTime
            {
                get
                {
                    return this.m_NextStateNormalizedTime;
                }
                set
                {
                    this.m_NextStateNormalizedTime = value;
                }
            }
            public Transition currentTransition
            {
                get
                {
                    return this.m_CurrentTransition;
                }
                set
                {
                    this.m_CurrentTransition = value;
                }
            }
            public float currentTransitionProgress
            {
                get
                {
                    return this.m_CurrentTransitionProgress;
                }
                set
                {
                    this.m_CurrentTransitionProgress = value;
                }
            }
            public void Clear()
            {
                this.m_CurrentState = null;
                this.m_NextState = null;
                this.m_CurrentStateNormalizedTime = 0f;
                this.m_NextStateNormalizedTime = 0f;
                this.m_CurrentTransition = null;
                this.m_CurrentTransitionProgress = 0f;
            }
        }
    }
}

